package org.noote.roby.pad;

import org.noote.libs.bluetooth.SPPClient;
import org.noote.libs.roby.comm.BluetoothCommandEvents;
import org.noote.libs.roby.comm.BluetoothCommandProtocol;
import org.noote.libs.roby.scan.ScanBitmapFactory;
import org.noote.libs.roby.scan.ScanResult;
import org.noote.libs.roby.configuration.RobotSettings;
import org.noote.libs.roby.configuration.RobotStates;
import org.noote.libs.virtualpad.Virtual5DPad;
import org.noote.libs.virtualpad.VirtualTouchPad;

import android.app.Activity;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.FrameLayout;
import android.widget.Toast;

public class Remote_Activity extends Activity {

	static final String TAG = "Remote_Activity";
	static final String BT_ADDRESS_DEVICE = "BtAddressDevice";

	private String _sAddressDevice;
	SPPClient _SPPClient = null;
	
	VirtualTouchPad _padTurret = null;
	Virtual5DPad _padTank = null;

	DisplayView _viewDisplay = null;
	int _iReadyStep = 0;
	
	int _iScan_Color = 3;
	int _iScan_Color_Max = 5;
	int _iScan_Correction = 1;
	
	int iFun1_Order = 0;
	
	boolean _bMultiTouch = false;
	
	RobotSettings _settings = new RobotSettings();
	RobotStates _states = new RobotStates();
	
	boolean _bInScanMode = false;
	protected static final int SCANPROGRESS_START = 0;
	protected static final int SCANPROGRESS_MSG = 1;
	protected static final int SCANPROGRESS_FINISH = 2;
	protected ProgressDialog m_mScanProgressDialog = null;
	
	protected static final int MESSAGE_UI_TOAST = 0;
	
	protected ScanBitmapFactory _scanBitmapFactory = new ScanBitmapFactory();
	protected ScanResult _latest_scan = null;
	
	PowerManager.WakeLock wl = null;

	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.remote);

        _SPPClient = new SPPClient(mBTEvents);
        
        FrameLayout frameDisplay = (FrameLayout) findViewById(R.id.frameDisplay);
        _viewDisplay = new DisplayView(this);
		_viewDisplay._settings = _settings;
		_viewDisplay._states = _states;
		frameDisplay.addView(_viewDisplay);
		_viewDisplay.setOnTouchListener(new OnTouchListener()
		{
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				
				if(!_states._bReady) return true;
				
				_viewDisplay._padInput.touch(event, _bMultiTouch);
				
				if(_viewDisplay._padScanPer5.haveNewEvent())
				{
					if(_viewDisplay._padScanPer5.getButton() && _viewDisplay._padScanPer2.isLocked())
					{
						_viewDisplay._padScanPer2.setLock(false);
					}
					_viewDisplay._padScanPer5.resetNewEvent();
				}
				if(_viewDisplay._padScanPer2.haveNewEvent())
				{
					if(_viewDisplay._padScanPer2.getButton() && _viewDisplay._padScanPer5.isLocked())
					{
						_viewDisplay._padScanPer5.setLock(false);
					}
					_viewDisplay._padScanPer2.resetNewEvent();
				}
				if(_viewDisplay._padScanLine.haveNewEvent())
				{
					if(_viewDisplay._padScanLine.getButton() && !_bInScanMode)
					{
						mScanProgressHandler.sendMessage(mScanProgressHandler.obtainMessage(SCANPROGRESS_START, null));

						boolean bScanPer2 = _viewDisplay._padScanPer2.isLocked();
						boolean bScanPer5 = _viewDisplay._padScanPer5.isLocked();
						boolean bLrg = _viewDisplay._padLarge.isLocked();

						short minl=(short) ((bLrg)?_settings._iTurret_MinLow:_settings._iTurret_MidLow-_settings._iTurret_Low_ShortAngle);
						short maxl=(short) ((bLrg)?_settings._iTurret_MaxLow:_settings._iTurret_MidLow+_settings._iTurret_Low_ShortAngle);
						short stepl=(short) ((bScanPer5)?5:(bScanPer2)?2:1);
						short h=(short)_settings._iTurret_MidHigh;

						// do a scan line radar !
						_SPPClient.sendMessage(BluetoothCommandProtocol.sendTurretScanLine(minl, maxl, stepl, h));
					}
					
					_viewDisplay._padScanLine.resetNewEvent();
				}
				if(_viewDisplay._padScanRadar.haveNewEvent())
				{
					if(_viewDisplay._padScanRadar.getButton() && !_bInScanMode)
					{
						mScanProgressHandler.sendMessage(mScanProgressHandler.obtainMessage(SCANPROGRESS_START, null));
						
						boolean bScanPer2 = _viewDisplay._padScanPer2.isLocked();
						boolean bScanPer5 = _viewDisplay._padScanPer5.isLocked();
						boolean bLrg = _viewDisplay._padLarge.isLocked();
						
						short minl=(short) ((bLrg)?_settings._iTurret_MinLow:_settings._iTurret_MidLow-_settings._iTurret_Low_ShortAngle);
						short maxl=(short) ((bLrg)?_settings._iTurret_MaxLow:_settings._iTurret_MidLow+_settings._iTurret_Low_ShortAngle);
						short stepl=(short) ((bScanPer5)?5:(bScanPer2)?2:1);
						short minh=(short) ((bLrg)?_settings._iTurret_MinHigh:_settings._iTurret_MidHigh-_settings._iTurret_High_ShortAngle);
						short maxh=(short) ((bLrg)?_settings._iTurret_MaxHigh:_settings._iTurret_MidHigh+_settings._iTurret_High_ShortAngle);
						short steph=(short) ((bScanPer5)?5:(bScanPer2)?2:1);
						
						// do a scan radar !
						_SPPClient.sendMessage(BluetoothCommandProtocol.sendTurretScanZone(minl, maxl, stepl, minh, maxh, steph));
					}
					
					_viewDisplay._padScanRadar.resetNewEvent();
				}
				if(_viewDisplay._padReport.haveNewEvent())
				{
					if(_viewDisplay._padReport.getButton())
					{
						_states._bReport_Transmission = _viewDisplay._padReport.isLocked();
						
						// enable/stop report transmission
						_SPPClient.sendMessage(BluetoothCommandProtocol.sendSetSendStatus(_states._bReport_Transmission));
					}
					
					_viewDisplay._padReport.resetNewEvent();
				}
				if(_viewDisplay._padScanColor.haveNewEvent())
				{
					if(_viewDisplay._padScanColor.getButton())
					{
						if(_latest_scan != null)
						{
							_iScan_Color = (_iScan_Color+1)%_scanBitmapFactory.getColorSchemeCount();
	
							// redraw last scan
							Bitmap bitmap = _scanBitmapFactory.createFrom(_settings, _iScan_Color, _latest_scan);
							if(bitmap != null)
								_viewDisplay.prepareImageRadar(bitmap);
						}
					}
					
					_viewDisplay._padScanColor.resetNewEvent();
				}
				if(_viewDisplay._padFun1.haveNewEvent())
				{
					if(_viewDisplay._padFun1.getButton())
					{
						int iTruc = 0;
						if(iTruc == 1)
						{
							switch(iFun1_Order)
							{
							case 0:	_SPPClient.sendMessage(BluetoothCommandProtocol.sendBodyRotateToTarget(_states._iBody_Speed, (0))); break;
							case 1:	_SPPClient.sendMessage(BluetoothCommandProtocol.sendBodyRotateToTarget(_states._iBody_Speed, (90))); break;
							case 2:	_SPPClient.sendMessage(BluetoothCommandProtocol.sendBodyRotateToTarget(_states._iBody_Speed, (180))); break;
							case 3:	_SPPClient.sendMessage(BluetoothCommandProtocol.sendBodyRotateToTarget(_states._iBody_Speed, (270))); break;
							}
							iFun1_Order = (iFun1_Order+1)%4;
						}
						else
						{
							switch(iFun1_Order)
							{
							case 0:	_SPPClient.sendMessage(BluetoothCommandProtocol.sendBodyMoveToTarget(_states._iBody_Speed, true, 10)); break;
							case 1:	_SPPClient.sendMessage(BluetoothCommandProtocol.sendBodyMoveToTarget(_states._iBody_Speed, false, 10)); break;
							}
							iFun1_Order = (iFun1_Order+1)%2;
						}
					}
					
					_viewDisplay._padFun1.resetNewEvent();
				}
				if(_viewDisplay._padTurretSensors.haveNewEvent())
				{
					if(_viewDisplay._padTurretSensors.getButton())
					{
						if(_settings._iRay_Sensors == 1)
							_settings._iRay_Sensors = 2;
						else if(_settings._iRay_Sensors == 2)
							_settings._iRay_Sensors = 1|2;
						else if(_settings._iRay_Sensors == (1|2))
							_settings._iRay_Sensors = 1;
						
						// set actives sensors for turret
						_SPPClient.sendMessage(BluetoothCommandProtocol.sendSetSettingRaySensors(_settings._iRay_Sensors));
					}

					_viewDisplay._padTurretSensors.resetNewEvent();
				}
				if(_viewDisplay._padLockTurretHigh.haveNewEvent())
				{
					_viewDisplay._padLockTurretHigh.resetNewEvent();
				}
				if(_viewDisplay._padBody.haveNewEvent())
				{
					if(_viewDisplay._padBody.getTouch()<0.5f || _viewDisplay._padBody.getButtonCenter())
					{
						// stop tout mouvement du vehicule !
						_SPPClient.sendMessage(BluetoothCommandProtocol.sendResetBody());
					}
					else
					{
						// ondule ton corps
						if(_viewDisplay._padBody.getButtonUp())
							_SPPClient.sendMessage(BluetoothCommandProtocol.sendBodyFront(_states._iBody_Speed)); // go front
						else if(_viewDisplay._padBody.getButtonDown())
							_SPPClient.sendMessage(BluetoothCommandProtocol.sendBodyBack(_states._iBody_Speed)); // go back
						else if(_viewDisplay._padBody.getButtonLeft())
							_SPPClient.sendMessage(BluetoothCommandProtocol.sendBodyLeft(_states._iBody_Speed)); // rotate left
						else if(_viewDisplay._padBody.getButtonRight())
							_SPPClient.sendMessage(BluetoothCommandProtocol.sendBodyRight(_states._iBody_Speed)); // rotate right
					}
					_viewDisplay._padBody.resetNewEvent();
					_viewDisplay.postInvalidate();
				}
				if(_viewDisplay._padBodySpeed.haveNewEvent())
				{
					if(_viewDisplay._padBodySpeed.getTouch()<0.5f)
					{
						// set vehicule speed !
						_states._iBody_Speed = _settings._iBody_MinSpeed+(int)((1.0-_viewDisplay._padBodySpeed.getPosition())*_settings._iBody_MaxSpeed);
					}
					_viewDisplay._padBodySpeed.resetNewEvent();
					_viewDisplay.postInvalidate();
				}
				if(_viewDisplay._padReinitTurret.haveNewEvent())
				{
					if(_viewDisplay._padReinitTurret.getButton())
					{
						// reinit turret
						_SPPClient.sendMessage(BluetoothCommandProtocol.sendResetTurret());
						_viewDisplay._padTurret.reset();
						_viewDisplay.postInvalidate();
					}
					_viewDisplay._padReinitTurret.resetNewEvent();
				}
				if(_viewDisplay._padTurret.haveNewEvent())
				{
					if(_viewDisplay._padTurret.getTouch()>0.5f)
					{
						boolean bLrg = _viewDisplay._padLarge.isLocked();
						boolean bLockH = _viewDisplay._padLockTurretHigh.isLocked();
						
						short iLow = (short) _settings._iTurret_MidLow;
						short iHigh = (short) _settings._iTurret_MidHigh;
						
						float fL = _viewDisplay._padTurret.getX();
						float fH = -_viewDisplay._padTurret.getY();
						
						if(bLrg)
						{
							if(fL>0)		iLow += (short) ((_settings._iTurret_MaxLow-_settings._iTurret_MidLow)*fL);
							else if(fL<0)	iLow -= (short) ((_settings._iTurret_MinLow-_settings._iTurret_MidLow)*fL);
							
							if(!bLockH)
							{
								if(fH>0)		iHigh += (short) ((_settings._iTurret_MaxHigh-_settings._iTurret_MidHigh)*fH);
								else if(fH<0)	iHigh -= (short) ((_settings._iTurret_MinHigh-_settings._iTurret_MidHigh)*fH);
							}
						}
						else
						{
							iLow += (short) ((_settings._iTurret_Low_ShortAngle)*fL);
							if(!bLockH)							
								iHigh += (short) ((_settings._iTurret_High_ShortAngle)*fH);
						}
						_SPPClient.sendMessage(BluetoothCommandProtocol.sendTurretSetPosition(iLow, iHigh));
					}
					_viewDisplay._padTurret.resetNewEvent();
					_viewDisplay.postInvalidate();
				}
		        // consume motion event
		        return true;
			}
		});
		
		Bundle bundle = this.getIntent().getExtras();
		_sAddressDevice = bundle.getString(BT_ADDRESS_DEVICE);
	}

   private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            // When discovery finds a device
            if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
				_states._bBluetoothOnline = false;
				_viewDisplay.setTargetMessage("Disconnected...");            	
            }
        }
    };
 
	final BluetoothCommandEvents mBTEvents = new BluetoothCommandEvents()
	{
		@Override
		public void onConnected()
		{
			sendToast("Connected");
			
			_states._bBluetoothOnline = true;
			_viewDisplay.setTargetMessage("Online...");
			_SPPClient.sendMessage(BluetoothCommandProtocol.sendAskVersion()); // ask version
			_SPPClient.sendMessage(BluetoothCommandProtocol.sendAskSetting()); // check report sending.
			_SPPClient.sendMessage(BluetoothCommandProtocol.sendAskSettingBody()); // get body setting
			_SPPClient.sendMessage(BluetoothCommandProtocol.sendAskSettingTurret()); // get turret setting
			_SPPClient.sendMessage(BluetoothCommandProtocol.sendAskSettingRay()); // get ray setting
		}
		@Override
		public void onDisconnected()
		{
			sendToast("Disconnected");
			
        	_states._bBluetoothOnline = false;
        	_states._bReady = false;
        	
        	_iReadyStep=0;
        	isReady();
		}
		@Override
		public void onError(String sError)
		{
			sendToast("Get Error : " + sError);
       	}
		@Override
		public void onText(String sText)
		{
			sendToast("Get text : " + sText);
		}
		@Override
		public void onVersion(String robotname, String robotversion)
		{
			_iReadyStep |= 0x01;
			
			_settings._sRobot_Name = robotname;
			_settings._sRobot_Version = robotversion;
			
			isReady();
		}
		@Override
		public void onSettings(boolean bReport_Transmission) {
			_states._bReport_Transmission =  bReport_Transmission;
			_viewDisplay._padReport.setLock(_states._bReport_Transmission);
			_viewDisplay.postInvalidate();			        		
			_iReadyStep |= 0x02;
			
			isReady();
		}
		@Override
		public void onBodySettings(int iBody_MinSpeed, int iBody_MidSpeed,
				int iBody_MaxSpeed, int iBody_MinDist, int iBody_MaxDist) {
			_settings._iBody_MinSpeed =  iBody_MinSpeed;
			_settings._iBody_MidSpeed =  iBody_MidSpeed;
			_settings._iBody_MaxSpeed =  iBody_MaxSpeed;
			_settings._iBody_MinDist =  iBody_MinDist;
			_settings._iBody_MaxDist =  iBody_MaxDist;
		
			_viewDisplay._padBodySpeed.setPosition((float)(_settings._iBody_MidSpeed-_settings._iBody_MinSpeed)/(float)(_settings._iBody_MaxSpeed-_settings._iBody_MinSpeed));
			_viewDisplay.postInvalidate();
			_iReadyStep |= 0x04;
			
			isReady();
		}
		@Override
		public void onTurretSettings(int iTurret_MinLow, int iTurret_MidLow,
				int iTurret_MaxLow, int iTurret_MinHigh, int iTurret_MidHigh,
				int iTurret_MaxHigh, int iTurret_MinDist, int iTurret_MidDist,
				int iTurret_MaxDist) {
			_settings._iTurret_MinLow = iTurret_MinLow;
			_settings._iTurret_MidLow = iTurret_MidLow;
			_settings._iTurret_MaxLow = iTurret_MaxLow;
			_settings._iTurret_MinHigh = iTurret_MinHigh;
			_settings._iTurret_MidHigh = iTurret_MidHigh;
			_settings._iTurret_MaxHigh = iTurret_MaxHigh;
			_settings._iTurret_MinDist = iTurret_MinDist;
			_settings._iTurret_MidDist = iTurret_MidDist;
			_settings._iTurret_MaxDist = iTurret_MaxDist;
			_iReadyStep |= 0x08;
		
			isReady();
		}
		@Override
		public void onRaySettings(int iRay_Count, int iRay_Delay, int iRay_Sensors, float fRay_Precision)
		{
			_settings._iRay_Count = iRay_Count;
			_settings._iRay_Delay = iRay_Delay;
			_settings._iRay_Sensors = iRay_Sensors;
			_settings._fRay_Precision = fRay_Precision;
			_iReadyStep |= 0x10;
			_viewDisplay.postInvalidate();
			
			isReady();
		}
		@Override
		public void onHitSensors(boolean bBody_Switch_BackLeft,
				boolean bBody_Switch_BackCenter, boolean bBody_Switch_BackRight) {
			_states._bBody_Switch_BackLeft = bBody_Switch_BackLeft;
			_states._bBody_Switch_BackCenter = bBody_Switch_BackCenter;			        			
			_states._bBody_Switch_BackRight = bBody_Switch_BackRight;
			_viewDisplay.postInvalidate();
		}
		@Override
		public void onLatestDistance(float fBody_LastMoveDistance_Left,
				float fBody_LastMoveDistance_Right) {
			_states._fBody_LastMoveDistance_Left = fBody_LastMoveDistance_Left;
			_states._fBody_LastMoveDistance_Right = fBody_LastMoveDistance_Right;
			_viewDisplay.postInvalidate();
		}
	    @Override
		public void onTurretInformation(int iTurret_Low, int iTurret_High,
				int iTurret_Distance) {
			_states._iTurret_Low = iTurret_Low;
			_states._iTurret_High = iTurret_High;
			_states._iTurret_Distance = iTurret_Distance;
			_viewDisplay.postInvalidate();			        		
		}
	    @Override
		public void onBodyInformation(float fBody_Bear, float fBody_Pitch,
				float fBody_Roll, int iBody_Distance) {
			_states._fBody_Bear =  fBody_Bear;
			_states._fBody_Pitch = fBody_Pitch;
			_states._fBody_Roll = fBody_Roll;
			_states._iBody_Distance = iBody_Distance;
			_viewDisplay.postInvalidate();			        		
		}
		@Override
		public void onScan(ScanResult scan) {
			mScanProgressHandler.sendMessage(mScanProgressHandler.obtainMessage(SCANPROGRESS_START, null));
			mScanProgressHandler.sendMessage(mScanProgressHandler.obtainMessage(SCANPROGRESS_MSG, "Analysing datas..."));

			_viewDisplay._latest_scan = _latest_scan = scan;
			if(_iScan_Correction>=1)
				scan.correction();
			if(_iScan_Correction>=2)
				scan.smooth();
			Bitmap bitmap = _scanBitmapFactory.createFrom(_settings, _iScan_Color, scan);
			if(bitmap != null)
				_viewDisplay.prepareImageRadar(bitmap);
			
    		mScanProgressHandler.sendMessage(mScanProgressHandler.obtainMessage(SCANPROGRESS_FINISH, null));
		}	    
		
		private void isReady()
		{
    		if(_states._bReady == false && _iReadyStep == (0x01|0x02|0x04|0x08|0x10))
    		{
    			_states._bReady = true;
    			_viewDisplay.setTargetMessage("");
    			if(!_states._bReport_Transmission)
        			_SPPClient.sendMessage(BluetoothCommandProtocol.sendSetSendStatus(true));

    			// force ray settings !
    			_SPPClient.sendMessage(BluetoothCommandProtocol.sendSetSettingRayCount(10));
    			_SPPClient.sendMessage(BluetoothCommandProtocol.sendSetSettingRayDelay(5));
    			_SPPClient.sendMessage(BluetoothCommandProtocol.sendSetSettingRayPrecision(0.10f));
    			_SPPClient.sendMessage(BluetoothCommandProtocol.sendSetSettingRaySensors(3));
    		}
    		else if(_states._bReady == false)
    		{
    			String sWait = "Wait ";
    			sWait += ((_iReadyStep & 0x01) == 0x01)?"*":".";
    			sWait += ((_iReadyStep & 0x02) == 0x02)?"*":".";
    			sWait += ((_iReadyStep & 0x04) == 0x04)?"*":".";
    			sWait += ((_iReadyStep & 0x08) == 0x08)?"*":".";
    			sWait += ((_iReadyStep & 0x10) == 0x10)?"*":".";
    			_viewDisplay.setTargetMessage(sWait);
    		}
		}
	};

	@Override
    public void onStart() {
        super.onStart();

        // Register for broadcasts when a device is disconnected !
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        this.registerReceiver(mReceiver, filter);
	}
	
	@Override
	public void onResume()
	{
		super.onResume();
		
		if(wl == null)
		{
			PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
		    wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "Remote Robot");
		}
		if(wl != null ) wl.acquire();
		
		_viewDisplay.setTargetMessage("Try connection...");
		if(!_SPPClient.isConnected())
		{
			if(!_SPPClient.connect(_sAddressDevice))
			{
				Toast.makeText(this, "Cannot connect :(", Toast.LENGTH_LONG).show();    	
				_viewDisplay.setTargetMessage("Connection impossible !!!");
			}
		}
	}
	
	@Override
	public void onPause()
	{
		super.onPause();
		
		if(_SPPClient.isConnected())
		{
			// TODO close it :)
		}
		if(wl != null ) wl.release();
	}
	@Override
	public void onStop()
	{
		this.unregisterReceiver(mReceiver);
		
		super.onStop();
	}
	
	final Handler mScanProgressHandler = new Handler() {
	    @Override
		public void handleMessage(Message msg) {
	        switch (msg.what) {
	        case SCANPROGRESS_START:
	        	if(_bInScanMode)
	        		break;
	        	
	        	if(m_mScanProgressDialog != null)
	        		m_mScanProgressDialog.dismiss();
            	m_mScanProgressDialog = ProgressDialog.show(Remote_Activity.this, "Scanning", "wait...", true);

	            _bInScanMode = true;
	            break;
	        case SCANPROGRESS_MSG:
	            if (m_mScanProgressDialog!=null && m_mScanProgressDialog.isShowing()) {
	            	m_mScanProgressDialog.setMessage(((String) msg.obj));
	            }
	            break;
	        case SCANPROGRESS_FINISH:
	            if (m_mScanProgressDialog!=null && m_mScanProgressDialog.isShowing()) {
	            	m_mScanProgressDialog.dismiss();
	            	m_mScanProgressDialog = null;
	            }
	            _bInScanMode = false;
	            break;
	        }
	    }
	};
	
	public void sendToast(String sMsg)
	{
		_UI_Handler.sendMessage(_UI_Handler.obtainMessage(MESSAGE_UI_TOAST, sMsg));
	}
	
	final Handler _UI_Handler = new Handler() {
	    @Override
		public void handleMessage(Message msg) {
	        switch (msg.what) {
	        case MESSAGE_UI_TOAST:
	        {
	        	Toast.makeText(getApplicationContext(), (String)msg.obj, Toast.LENGTH_LONG).show();
	        }
	            break;
	        }
	    }
	};
}
